﻿using System;
using System.Collections.Generic;

using System.Text;
using System.Windows;
using System.Reflection;
using System.Reflection.Emit;
using Phydeaux.Utilities;
using System.Windows.Controls.Primitives;

namespace Bixas.Tangibilis.Utility
{
    public class SafeSecurityHelperWrapper
    {
        private static Phydeaux.Utilities.Func<UIElement, Point, Point> _ClientToScreenWrapper;
       static SafeSecurityHelperWrapper()
        {
            InitWrappers();
        }

   

        public static Point ClientToScreen(UIElement relativeTo, Point point)
        {
            return _ClientToScreenWrapper(relativeTo, point);
        }

        private static void InitWrappers()
        {
            #region Init ExecuteCommandSource method wrapper

            //retrieve internal type MS.Internal.Commands.CommandHelpers
            Type commandHelpersType = System.Reflection.Assembly.GetAssembly(typeof(Thumb))
                                                            .GetType("MS.Internal.PresentationFramework.SafeSecurityHelper");
            //retrieve internal procedure ExecuteCommandSource(ICommandSource commandSource)
            MethodInfo ClientToScreenMethod = commandHelpersType.GetMethod("ClientToScreen", System.Reflection.BindingFlags.NonPublic | BindingFlags.Static);
            //create a new DynamicMethod to create a wrapper to call the required method
            DynamicMethod dm = new DynamicMethod(ClientToScreenMethod.Name,
                                                 MethodAttributes.Static | MethodAttributes.Public, // public static
                                                 CallingConventions.Standard,
                                                 typeof(Point),
                                                 new Type[] { typeof(UIElement), typeof(Point) },
                                                 commandHelpersType,
                                                 true);
            dm.InitLocals = false;

            //use Phydeaux codeEmit wrapper for clener code
            DynamicEmit de = new DynamicEmit(dm);
            de.LoadArgument(0);
            de.LoadArgument(1);
            de.Call(ClientToScreenMethod);
            //TODO: verify if cast is needed when return type is void
            de.CastTo(ClientToScreenMethod.ReturnType, typeof(Point));
            de.Return();
            //Retrieve a typed delegate targeting the created wrapper method
            _ClientToScreenWrapper = (Phydeaux.Utilities.Func<UIElement, Point, Point>)dm.CreateDelegate(typeof(Phydeaux.Utilities.Func<UIElement, Point, Point>));


           
            #endregion
        }
    }
}
